package com.zzh.partnersys.ai.controller;

import cn.hutool.core.util.StrUtil;
import com.zzh.partnersys.ai.chat.AiChatApp;
import com.zzh.partnersys.ai.entity.request.AiStreamRequest;
import com.zzh.partnersys.ai.util.RedisSequenceUtil;
import com.zzh.partnersys.common.enums.ChatTypeEnum;
import com.zzh.partnersys.common.util.TokenUtils;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.ai.tool.ToolCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerSentEvent;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import reactor.core.publisher.Flux;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@RestController
@RequestMapping("/chat")
public class AIChatController {
    //todo 后续拓展可能支持图片多模态，解析图片转文字一同放入prompt中，如果是流程图则要采取图文模型解析

    @Resource
    private AiChatApp aiChatApp;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Resource
    private RedisSequenceUtil redisSequenceUtil;

    @Resource
    private ToolCallback[] allTools;

    /**
     * SSE 流式调用 AI 助手应用
     *  这个用Flux封装流式数据，后端自动在请求头中添加Content-Type: text/event-stream;charset=UTF-8
     * @param message  聊天消息
     * @param chatId 会话ID
     * @return Flux<String> 流式数据
     */
    @GetMapping(value = "/sse", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> doChatWithAiChatAppSSE(String message, String chatId, Long assistantId, HttpServletRequest request) {
        return aiChatApp.doChatWithStream(message, chatId,assistantId,request);
    }

    /**
     * SSE 流式调用 AI 助手应用
     * 这个用ServerSentEvent封装流式数据，后端自动在请求头中添加Content-Type: text/event-stream;charset=UTF-8
     * @param message
     * @param chatId
     * @return
     */
    @GetMapping(value = "/server_sent_event")
    public Flux<ServerSentEvent<String>> doChatWithLoveAppServerSentEvent(String message, String chatId, Long assistantId, HttpServletRequest request) {
        return aiChatApp.doChatWithStream(message, chatId,assistantId,request)
                .map(chunk -> ServerSentEvent.<String>builder()
                        .data(chunk)
                        .build());
    }

    /**
     * 流式调用 AI 助手应用（供IM模块远程调用）
     * 仅负责大模型流式调用，不处理业务逻辑
     * 返回 Flux<String> 供 WebClient 订阅，不能返回 SseEmitter（SseEmitter 无法通过 HTTP 远程传递）
     *
     * @param request 请求对象，包含message、sessionId、assistantId
     * @return Flux<String> 流式数据
     */
    @PostMapping(value = "/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public Flux<String> streamChat(@RequestBody AiStreamRequest request,HttpServletRequest httpServletRequest) {
        String message = request.getMessage();
        String sessionId = request.getSessionId();
        Long assistantId = request.getAssistantId();
        
        if (message == null || sessionId == null || assistantId == null) {
            return Flux.just("参数错误：message、sessionId、assistantId不能为空");
        }
        
        return aiChatApp.doChatWithStream(message, sessionId, assistantId,httpServletRequest);
    }

    /**
     * SSE 流式调用 AI 助手应用（直接前端调用，不推荐用于微服务间调用）
     * 注意：SseEmitter 不能通过 HTTP 远程传递，只能用于直接的前端调用
     * 
     * @deprecated 此方法仅用于直接前端调用，微服务间调用请使用 /chat/stream 接口
     */
    @GetMapping(value = "/chat/sse_emitter")
    public SseEmitter doChatWithLoveAppServerSseEmitter(String message, String chatId, Long assistantId,HttpServletRequest httpServletRequest) {
        // 创建一个超时时间较长的 SseEmitter
        SseEmitter sseEmitter = new SseEmitter(600000L); // 10 分钟超时
        // 获取 Flux 响应式数据流并且直接通过订阅推送给 SseEmitter
        aiChatApp.doChatWithStream(message, chatId, assistantId,httpServletRequest)
                .subscribe(chunk -> {
                    try {
                        sseEmitter.send(chunk);
                    } catch (IOException e) {
                        sseEmitter.completeWithError(e);
                    }
                }, sseEmitter::completeWithError, sseEmitter::complete);
        // 返回
        return sseEmitter;
    }

    /**
     * SSE 流式调用 AI 助手应用（前端 EventSource 调用 - GET 方式）
     * EventSource 只支持 GET 请求，不支持 POST
     * 注意：GET 请求的 URL 长度有限制，如果消息很大，请使用 POST 接口 /sse_emitter
     * 
     * @param message 用户消息
     * @param sessionId 会话ID
     * @param assistantId 助手ID
     * @param request HttpServletRequest，用于获取用户ID
     * @return SseEmitter SSE 流
     */
    @GetMapping(value = "/sse_emitter")
    public SseEmitter doChatWithServerSseEmitterGet(
            @RequestParam("message") String message,
            @RequestParam("sessionId") String sessionId,
            @RequestParam("assistantId") Long assistantId,
            HttpServletRequest request) {
        // 获取用户ID（用于后续保存消息，目前相关代码已注释）
        Long userId = TokenUtils.getCurrentUserId(request);
        if (userId == null) {
            return senderSseEmitter("用户未登录");
        }

        // 1. 基础参数校验
        if (sessionId == null || assistantId == null || StrUtil.isEmpty(message)) {
            return senderSseEmitter("必填参数不能为空");
        }

        return createSseEmitter(message, sessionId, assistantId, request);
    }

    /**
     * SSE 流式调用 AI 助手应用（POST 方式，支持大消息） todo 后续优化 前端EventSource不支持?
     * @param aiStreamRequest 请求对象，包含 message、sessionId、assistantId
     * @param request HttpServletRequest，用于获取用户ID
     * @return SseEmitter SSE 流
     */
    @PostMapping(value = "/sse_emitter", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter doChatWithServerSseEmitter(
            @RequestBody AiStreamRequest aiStreamRequest,
            HttpServletRequest request) {
        String message = aiStreamRequest.getMessage();
        String sessionId = aiStreamRequest.getSessionId();
        Long assistantId = aiStreamRequest.getAssistantId();
        
        // 获取用户ID（用于后续保存消息，目前相关代码已注释）
        @SuppressWarnings("unused")
        Long userId = TokenUtils.getCurrentUserIdOrThrow(request);

        // 1. 基础参数校验
        if (sessionId == null || assistantId == null || StrUtil.isEmpty(message)) {
            return senderSseEmitter("必填参数不能为空");
        }

        return createSseEmitter(message, sessionId, assistantId, request);
    }

    /**
     * 创建 SseEmitter 并处理 AI 流式响应
     * 
     * @param message 用户消息
     * @param sessionId 会话ID
     * @param assistantId 助手ID
     * @return SseEmitter
     */
    private SseEmitter createSseEmitter(String message, String sessionId, Long assistantId,HttpServletRequest httpServletRequest) {

        //1.2 校验会话chat_session是否存在 、 校验消息格式,校验content中的fileUrl是否有效


//        Long messageId = SnowflakeUtil.nextId();
        //todo 如果异常其实就会跳号了
        Long sequence = redisSequenceUtil.generateSequence(ChatTypeEnum.SINGLE_CHAT.getCode(), Long.valueOf(sessionId));
        // 会话 + 序列号 => 就能确保唯一性
        String messageId = sessionId + "_" + sequence;

        // 创建一个超时时间较长的 SseEmitter
        SseEmitter sseEmitter = new SseEmitter(600000L); // 10 分钟超时
        // 获取 Flux 响应式数据流并且直接通过订阅推送给 SseEmitter
        aiChatApp.doChatWithStream(message, sessionId, assistantId,httpServletRequest)
                .subscribe(chunk -> {
                    try {
                        System.out.println("收到AI回复：" + chunk);
                        // redisTemplate.opsForValue().append(streamContentKey, chunk);
                        sseEmitter.send(chunk);
                    } catch (IOException e) {
                        sseEmitter.completeWithError(e);
                    }
                }, error -> { // 异常回调
                    try {
                        sseEmitter.send(SseEmitter.event()
                                .name("error")
                                .data("AI回复异常：" + error.getMessage()));
                    } catch (IOException e) {
                        // 忽略
                    } finally {
                        // redisTemplate.opsForValue().set(streamStatusKey, "FAILED");
                        // 直接调用异步保存方法（不完整消息）
                        // saveIncompleteMessage(messageId, sessionId, assistantId, userId, sequence);
                        sseEmitter.completeWithError(error);
                    }
                }, () -> { // 完成回调
                    try {
                        Map<String, Object> completeData = new HashMap<>();
                        completeData.put("messageId", messageId);
                        completeData.put("sequence", sequence);
                        sseEmitter.send(SseEmitter.event()
                                .name("complete")
                                .data("AI回复完成"));
                    } catch (IOException e) {
                        // 忽略
                    } finally {
                        // redisTemplate.opsForValue().set(streamStatusKey, "COMPLETE");
                        // 直接调用异步保存方法（完整消息，不阻塞SSE完成）
                        // 获取AI完整回复内容
                        // String aiCompleteContent = (String) redisTemplate.opsForValue().get(streamContentKey);
                        //saveCompleteMessage(messageId, sessionId, assistantId, userId, sequence, aiCompleteContent);
                        sseEmitter.complete();
                    }
                });
        // 返回
        return sseEmitter;
    }

    private SseEmitter senderSseEmitter(String data){
        if (data == null){
            return senderSseEmitter("数据不能为空");
        }
        SseEmitter errorEmitter = new SseEmitter(1000L);
        try {
            errorEmitter.send(SseEmitter.event().name("error").data(data));
            errorEmitter.complete();
        } catch (IOException e) {
            log.error("发送错误信息失败", e);
        }
        return errorEmitter;
    }

}
